﻿using Hangfire;
using HungFire.Net5.Filter;
using HungFire.Net5.Jobs;
using HungFire.Net5.Jobs.Interface;
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Xml.Linq;
using static HungFire.Net5.Filter.TimeJobAttribute;

namespace HungFire.Net5
{
    public static class BaseJob
    {



        /// <summary>
        /// Job统一注册
        /// </summary>
        public static void RegisterJob(this IApplicationBuilder app, IBackgroundJobClient backgroundJobs)
        {




            //后台队列调用
            //backgroundJobs.Enqueue<IJobTest>(x => x.ExecuteTask_v1());
            ////延迟调用方法
            //backgroundJobs.Schedule<IJobTest>((x) => x.ExecuteTask_v1(), TimeSpan.FromMinutes(1));
            //var options = new BackgroundJobServerOptions
            //{
            //    SchedulePollingInterval = TimeSpan.FromMinutes(1)
            //};
            //var server = new BackgroundJobServer(options);
            var thisType = typeof(BaseJob);
            var dataNow = DateTime.Now;
            //获取继承了此类的所有type
            var types = Assembly.GetAssembly(thisType).GetTypes();
            foreach (Type jobType in types)
            {
                //if (jobType.IsInterface) 
                //    continue;//判断是否是接口
                //Type[] ins = jobType.GetInterfaces();
                if (jobType.Equals(thisType))
                    continue;
                var methods = jobType.GetMethods();
                foreach (MethodInfo mth in methods)
                {
                    var timeJobAttr = mth.GetCustomAttribute<TimeJobAttribute>();
                    if (timeJobAttr == null || mth.GetParameters().Length > 0)
                        continue;
                    //var parameters = mth.GetParameters();
                    //object[] parament = null;
                    //ParameterExpression[] parameterExpressions = null;
                    //if (parameters.Count() > 0)
                    //{
                    //    parament = new object[parameters.Length];
                    //    parameterExpressions = new ParameterExpression[parameters.Length];
                    //    var methodParameters = MethodParameterInfos().ToList().FirstOrDefault(x => x.MethodName.Equals(mth.Name));
                    //    if (methodParameters != null)
                    //    {
                    //        var parameterType = methodParameters.Parameters.GetType();
                    //        int i = 0;
                    //        foreach (var parameter in parameters)
                    //        {
                    //            var parameterName = parameter.Name;
                    //            var property = from pi in parameterType.GetProperties()
                    //                           where pi.Name.ToLower() == parameterName.ToLower()
                    //                           select pi;
                    //            var value = property.First().GetValue(methodParameters.Parameters, null);
                    //            parament[i] = value;
                    //            parameterExpressions[i] = Expression.Parameter(parameter.GetType(), value.ToString());
                    //            i++;
                    //        }
                    //    }
                    //}
                    //object obj = Activator.CreateInstance(jobType);
                    //mth.Invoke(obj, null);
                    ////Expression<Action> actionExp = () => mth.Invoke(obj, parament);
                    var jobTypeEnum = timeJobAttr.JobType;
                    var type = Expression.New(jobType);
                    var bodyExp = Expression.Call(type,mth);
                    var actionExp = Expression.Lambda<Action>(bodyExp);
                    switch (jobTypeEnum)
                    {
                        case JobTypeEnum.Enqueue:
                            EnqueueJob();
                            break;
                        case JobTypeEnum.Schedule:
                            ScheduleEnqueueJob();
                            break;
                        case JobTypeEnum.Cron:
                            CronJob();
                            break;
                    }

                    void EnqueueJob()
                    {
                        BackgroundJob.Enqueue(actionExp);
                    }
                    void ScheduleEnqueueJob()
                    {
                        var delayedTime = timeJobAttr.DelayedStartTime;
                        if (!string.IsNullOrWhiteSpace(delayedTime) && DateTime.TryParse(delayedTime, out DateTime dtDate) && dtDate > dataNow)
                        {
                            TimeSpan dataNowTime = new TimeSpan(dataNow.Ticks);
                            TimeSpan dtDateTime = new TimeSpan(dtDate.Ticks);
                            TimeSpan tsDiff = dtDateTime.Subtract(dataNowTime).Duration();
                            BackgroundJob.Schedule(actionExp, tsDiff);
                        }
                    }
                    void CronJob()
                    {
                        var jobName = timeJobAttr.JobName ?? mth.Name;
                        var jobCron = string.IsNullOrEmpty(timeJobAttr.CronExpression) ? Cron.Daily() : timeJobAttr.CronExpression;
                        if (!timeJobAttr.EnableStatus)
                            RecurringJob.RemoveIfExists(jobName);//移除任务
                        RecurringJob.AddOrUpdate(jobName, actionExp, jobCron);
                    }
                }
            }

            //RecurringJob.RemoveIfExists("测试任务1"); 
            //执行循环任务
            //Corn 每秒执行一次

            //var cronSecond = "1 * * * * ? ";
            //var jobCode = "easyjob";
            //var jobTest = new JobTest();
            //RecurringJob.AddOrUpdate(jobCode, () => jobTest.ExecuteTask_v2(4), cronSecond);
            //移除任务
            //RecurringJob.RemoveIfExists("easyjob");
            //立即执行重复作业
            //RecurringJob.Trigger(jobCode);

            ///批次处理 ，需安装Hangfire.Pro，但没有找到
            //BatchJob.ContinueBatchWith(antecedentId, continuation =>
            //{
            //    continuation.StartNew(inner => inner.Enqueue(() => Console.WriteLine("First")));
            //    continuation.StartNew(inner => inner.Enqueue(() => Console.WriteLine("Second")));
            //});
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<MethodParameterInfo> MethodParameterInfos()
        {
            List<MethodParameterInfo> methodParameterInfos = new List<MethodParameterInfo>
            {
                new MethodParameterInfo
                {
                    MethodName ="ExecuteTask_v1",
                    Parameters=new {
                        beginTime =DateTime.Now,
                        endTime = DateTime.Now.AddDays(1)
                    }
                },
                new MethodParameterInfo
                {
                  MethodName ="ExecuteTask_v2",
                    Parameters=new {
                        count =50
                    }

                }
            };
            return methodParameterInfos;
        }
    }
}
